module Account
    module AuthenticatedSystem
        
        protected
        # Inclusion hook to make #current_user and #logged_in?
        # available as ActionView helper methods.
        def self.included(base)
            base.send :helper_method, :current_user, :logged_in?, :is_authorized
        end
        
        # Returns true if a current user is found.
        # Preloads @current_user with the user model if they're logged in.
        def logged_in?
            !current_user.nil?
        end

        # Determine if the user has the right to perform some action
        # To be successful the current_user must either match the user
        # or be in the specified role
        def is_authorized(user, role)
            if logged_in?
                if !user.nil? && user.id == current_user.id || current_user.role == role
                    return true
                end
            end
            return false
        end
        
        # Use to protect a method from unauthorized access
        def restrict_access(user, role)
            redirect_to "/not_authorized" unless is_authorized(user, role)
        end       
                
        # Accesses the current user from the session.
        def current_user
            @current_user ||= (session[:user_id] && User.find_by_id(session[:user_id])) || nil
        end
        
        # Store the given user in the session.
        def current_user=(new_user)
            session[:user_id] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.id
            @current_user = new_user
        end
                
        # Enforce login
        #   i.e.
        #   before_filter :login_required
        #   before_filter :login_required, :only => [ :edit, :update ]
        # Skip login in a sub controller
        #   skip_before_filter :login_required
        def login_required
            if !logged_in?
                # not logged in.  Try to authenticate using basic http authentication
                username, passwd = get_auth_data
                if username && passwd
                    self.current_user = User.authenticate(username, passwd) 
                end
                
                login_from_url_key
                
                if !logged_in?
                    access_denied
                end
            end
        end
        
        # Redirect as appropriate when an access request fails.
        # The default action is to redirect to the login screen.
        # Override this method in your controllers if you want to have special
        # behavior in case the user is not authorized
        # to access the requested action.  For example, a popup window might
        # simply close itself.
        def access_denied
            
            respond_to do |accepts|
                accepts.html do
                    store_location
                    flash[:notice] = "Please sign in"
                    redirect_to "/signin"
                end
                accepts.xml do
                    headers["Status"]           = "Unauthorized"
                    headers["WWW-Authenticate"] = %(Basic realm="Web Password")
                    render :text => "Could't authenticate you", :status => '401 Unauthorized'
                end
            end
            false
        end  
        
        # Store the URI of the current request in the session.
        #
        # We can return to this location by calling #redirect_back_or_default.
        def store_location(store_uri=request.request_uri)
            session[:return_to] = store_uri
        end
        
        # Redirect to the URI stored by the most recent store_location call or
        # to the passed default.
        def redirect_back_or_default(default)
            session[:return_to] ? redirect_to_url(session[:return_to]) : redirect_to(default)
            session[:return_to] = nil
        end
        
        # When called with before_filter :login_from_cookie will check for an :auth_token
        # cookie and log the user back in if apropriate
        def login_from_cookie
            return unless cookies[:auth_token] && !logged_in?
            user = User.find_by_remember_token(cookies[:auth_token])
            if user && user.remember_token?
                user.remember_me
                self.current_user = user
                cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
                flash[:notice] = "Logged in successfully"
            end
        end
        
        def login_from_url_key
            if not params[:key].nil?
                key = params[:key]
                # authenticate using the key
                self.current_user = User.authenticate_by_api_key(key) 
            end
        end
        
        private
        @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
        # gets BASIC auth info
        def get_auth_data
            auth_key  = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
            auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
            return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil] 
        end
    end
end